package service

import (
	"fmt"
	"log"
	"math/rand"
	"sort"
	"sync"
	"time"

	"github.com/slrun/callcenter/internal/model"
	"github.com/slrun/callcenter/internal/pkg/freeswitch"
)

// ACDEngine ACD智能呼叫分配引擎
type ACDEngine struct {
	fsClient          *freeswitch.Client
	queues            map[string]*model.Queue
	queueMembers      map[string]*model.QueueMember
	callQueueEntries  map[string]*model.CallQueueEntry
	callbacks         map[string]*model.CallbackRequest
	skills            map[string]*model.Skill
	agentSkills       map[string]*model.AgentSkill
	lastAgentIndex    map[string]int // 用于轮循策略
	mutex             sync.RWMutex
	agentActivity     map[string]*AgentActivity
}

// AgentActivity 座席活动信息
type AgentActivity struct {
	LastAvailableTime time.Time
	TotalTalkTime     int // 总通话时间(秒)
	TotalCalls        int // 总呼叫次数
}

// NewACDEngine 创建ACD引擎
func NewACDEngine(fsClient *freeswitch.Client) *ACDEngine {
	return &ACDEngine{
		fsClient:          fsClient,
		queues:            make(map[string]*model.Queue),
		queueMembers:      make(map[string]*model.QueueMember),
		callQueueEntries:  make(map[string]*model.CallQueueEntry),
		callbacks:         make(map[string]*model.CallbackRequest),
		skills:            make(map[string]*model.Skill),
		agentSkills:       make(map[string]*model.AgentSkill),
		lastAgentIndex:    make(map[string]int),
		agentActivity:     make(map[string]*AgentActivity),
	}
}

// 队列管理方法

// AddQueue 添加队列
func (e *ACDEngine) AddQueue(queue *model.Queue) {
	e.mutex.Lock()
	defer e.mutex.Unlock()
	e.queues[queue.ID] = queue
	e.lastAgentIndex[queue.ID] = 0
	log.Printf("Added queue: %s", queue.Name)
}

// UpdateQueue 更新队列
func (e *ACDEngine) UpdateQueue(queue *model.Queue) error {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	if _, exists := e.queues[queue.ID]; !exists {
		return fmt.Errorf("queue not found: %s", queue.ID)
	}

	e.queues[queue.ID] = queue
	log.Printf("Updated queue: %s", queue.Name)
	return nil
}

// RemoveQueue 移除队列
func (e *ACDEngine) RemoveQueue(queueID string) error {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	if _, exists := e.queues[queueID]; !exists {
		return fmt.Errorf("queue not found: %s", queueID)
	}

	// 处理队列中的呼叫
	for _, entry := range e.callQueueEntries {
		if entry.QueueID == queueID && entry.Status == "queued" {
			e.handleQueueOverflow(entry)
		}
	}

	// 移除队列成员
	for key, member := range e.queueMembers {
		if member.QueueID == queueID {
			delete(e.queueMembers, key)
		}
	}

	delete(e.queues, queueID)
	delete(e.lastAgentIndex, queueID)
	log.Printf("Removed queue: %s", queueID)
	return nil
}

// GetQueue 获取队列
func (e *ACDEngine) GetQueue(queueID string) (*model.Queue, error) {
	e.mutex.RLock()
	defer e.mutex.RUnlock()

	queue, exists := e.queues[queueID]
	if !exists {
		return nil, fmt.Errorf("queue not found: %s", queueID)
	}

	return queue, nil
}

// ListQueues 列出所有队列
func (e *ACDEngine) ListQueues() []*model.Queue {
	e.mutex.RLock()
	defer e.mutex.RUnlock()

	queues := make([]*model.Queue, 0, len(e.queues))
	for _, queue := range e.queues {
		queues = append(queues, queue)
	}

	return queues
}

// 队列成员管理

// AddAgentToQueue 添加座席到队列
func (e *ACDEngine) AddAgentToQueue(agentID, queueID string, priority int) error {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	// 检查队列是否存在
	if _, exists := e.queues[queueID]; !exists {
		return fmt.Errorf("queue not found: %s", queueID)
	}

	// 创建成员ID
	memberID := fmt.Sprintf("%s:%s", agentID, queueID)

	// 初始化座席活动信息
	if _, exists := e.agentActivity[agentID]; !exists {
		e.agentActivity[agentID] = &AgentActivity{
			LastAvailableTime: time.Now(),
			TotalTalkTime:     0,
			TotalCalls:        0,
		}
	}

	// 添加队列成员
	e.queueMembers[memberID] = &model.QueueMember{
		AgentID:         agentID,
		QueueID:         queueID,
		Priority:        priority,
		JoinTime:        time.Now(),
		Status:          model.AgentStatusLoggedIn,
		LastStateChange: time.Now(),
	}

	log.Printf("Added agent %s to queue %s with priority %d", agentID, queueID, priority)
	return nil
}

// RemoveAgentFromQueue 从队列移除座席
func (e *ACDEngine) RemoveAgentFromQueue(agentID, queueID string) error {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	memberID := fmt.Sprintf("%s:%s", agentID, queueID)
	if _, exists := e.queueMembers[memberID]; !exists {
		return fmt.Errorf("agent not found in queue: %s, %s", agentID, queueID)
	}

	delete(e.queueMembers, memberID)
	log.Printf("Removed agent %s from queue %s", agentID, queueID)
	return nil
}

// UpdateAgentStatus 更新座席状态
func (e *ACDEngine) UpdateAgentStatus(agentID, queueID string, status model.AgentStatus) error {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	memberID := fmt.Sprintf("%s:%s", agentID, queueID)
	member, exists := e.queueMembers[memberID]
	if !exists {
		return fmt.Errorf("agent not found in queue: %s, %s", agentID, queueID)
	}

	member.Status = status
	member.LastStateChange = time.Now()

	// 更新座席活动信息
	if status == model.AgentStatusAvailable {
		if activity, exists := e.agentActivity[agentID]; exists {
			activity.LastAvailableTime = time.Now()
		}
	}

	log.Printf("Updated agent %s status to %s in queue %s", agentID, status, queueID)

	// 如果座席变为可用状态，尝试分配队列中的呼叫
	if status == model.AgentStatusAvailable {
		go e.processQueue(queueID)
	}

	return nil
}

// GetAvailableAgents 获取队列中可用的座席
func (e *ACDEngine) GetAvailableAgents(queueID string) []*model.QueueMember {
	e.mutex.RLock()
	defer e.mutex.RUnlock()

	var availableAgents []*model.QueueMember
	for _, member := range e.queueMembers {
		if member.QueueID == queueID && member.Status == model.AgentStatusAvailable {
			availableAgents = append(availableAgents, member)
		}
	}

	return availableAgents
}

// 呼叫入队和分配

// EnqueueCall 呼叫入队
func (e *ACDEngine) EnqueueCall(queueID, callUUID, callerID string, priority int, skillsNeeded []string) (*model.CallQueueEntry, error) {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	// 检查队列是否存在
	queue, exists := e.queues[queueID]
	if !exists {
		return nil, fmt.Errorf("queue not found: %s", queueID)
	}

	// 检查队列状态
	if queue.Status != model.QueueStatusActive {
		return nil, fmt.Errorf("queue not active: %s", queueID)
	}

	// 检查队列大小限制
	queueCount := e.getQueueSize(queueID)
	if queue.MaxQueueSize > 0 && queueCount >= queue.MaxQueueSize {
		// 队列已满，处理溢出
		entry := &model.CallQueueEntry{
			ID:           fmt.Sprintf("entry_%s", callUUID),
			QueueID:      queueID,
			CallUUID:     callUUID,
			CallerID:     callerID,
			Priority:     priority,
			JoinTime:     time.Now(),
			Position:     queueCount + 1,
			WaitTime:     0,
			SkillsNeeded: skillsNeeded,
			Status:       "queued",
		}
		e.handleQueueOverflow(entry)
		return entry, fmt.Errorf("queue full, overflow handled")
	}

	// 创建队列条目
	entry := &model.CallQueueEntry{
		ID:           fmt.Sprintf("entry_%s", callUUID),
		QueueID:      queueID,
		CallUUID:     callUUID,
		CallerID:     callerID,
		Priority:     priority,
		JoinTime:     time.Now(),
		Position:     queueCount + 1,
		WaitTime:     0,
		SkillsNeeded: skillsNeeded,
		Status:       "queued",
	}

	e.callQueueEntries[entry.ID] = entry
	log.Printf("Call %s from %s enqueued in %s at position %d", callUUID, callerID, queueID, entry.Position)

	// 更新所有队列条目的位置
	e.updateQueuePositions(queueID)

	// 异步处理队列
	go e.processQueue(queueID)

	return entry, nil
}

// RemoveCallFromQueue 从队列移除呼叫
func (e *ACDEngine) RemoveCallFromQueue(entryID string) error {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	entry, exists := e.callQueueEntries[entryID]
	if !exists {
		return fmt.Errorf("queue entry not found: %s", entryID)
	}

	queueID := entry.QueueID
	delete(e.callQueueEntries, entryID)
	log.Printf("Call %s removed from queue %s", entry.CallUUID, queueID)

	// 更新队列位置
	e.updateQueuePositions(queueID)

	return nil
}

// processQueue 处理队列中的呼叫分配
func (e *ACDEngine) processQueue(queueID string) {
	for {
		// 选择最佳座席和呼叫
		agent, call := e.selectBestAgentAndCall(queueID)
		if agent == nil || call == nil {
			// 没有可用座席或呼叫
			break
		}

		// 分配呼叫
		e.assignCallToAgent(agent, call)
	}
}

// selectBestAgentAndCall 选择最佳座席和呼叫组合
func (e *ACDEngine) selectBestAgentAndCall(queueID string) (*model.QueueMember, *model.CallQueueEntry) {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	queue, exists := e.queues[queueID]
	if !exists {
		return nil, nil
	}

	// 获取所有可用座席
	availableAgents := e.getAvailableAgentsLocked(queueID)
	if len(availableAgents) == 0 {
		return nil, nil
	}

	// 获取队列中的呼叫并按优先级和等待时间排序
	calls := e.getQueueCallsLocked(queueID)
	if len(calls) == 0 {
		return nil, nil
	}

	// 根据分配策略选择座席
	var selectedAgent *model.QueueMember
	switch queue.Strategy {
	case model.ACDStrategyRoundRobin:
		selectedAgent = e.selectRoundRobinAgent(availableAgents, queueID)
	case model.ACDStrategyLongestIdle:
		selectedAgent = e.selectLongestIdleAgent(availableAgents)
	case model.ACDStrategyLeastTalkTime:
		selectedAgent = e.selectLeastTalkTimeAgent(availableAgents)
	case model.ACDStrategyLeastCalls:
		selectedAgent = e.selectLeastCallsAgent(availableAgents)
	case model.ACDStrategySkillBased:
		// 技能匹配需要考虑呼叫所需技能
		if len(calls) > 0 {
			selectedAgent = e.selectBestSkillMatchAgent(availableAgents, calls[0])
		}
	case model.ACDStrategyPriority:
		// 优先级策略按座席优先级选择
		selectedAgent = e.selectHighestPriorityAgent(availableAgents)
	default:
		// 默认使用轮循
		selectedAgent = e.selectRoundRobinAgent(availableAgents, queueID)
	}

	if selectedAgent == nil && len(availableAgents) > 0 {
		// 如果没有根据策略选出座席，选择第一个可用座席
		selectedAgent = availableAgents[0]
	}

	// 返回最佳座席和第一个呼叫
	return selectedAgent, calls[0]
}

// 分配策略实现

// selectRoundRobinAgent 轮循选择座席
func (e *ACDEngine) selectRoundRobinAgent(agents []*model.QueueMember, queueID string) *model.QueueMember {
	if len(agents) == 0 {
		return nil
	}

	index := e.lastAgentIndex[queueID]
	selected := agents[index%len(agents)]
	e.lastAgentIndex[queueID] = index + 1

	return selected
}

// selectLongestIdleAgent 选择最长空闲时间的座席
func (e *ACDEngine) selectLongestIdleAgent(agents []*model.QueueMember) *model.QueueMember {
	if len(agents) == 0 {
		return nil
	}

	sort.Slice(agents, func(i, j int) bool {
		// 获取座席活动信息
		activityI, existsI := e.agentActivity[agents[i].AgentID]
		activityJ, existsJ := e.agentActivity[agents[j].AgentID]

		// 默认返回较早加入的座席
		if !existsI || !existsJ {
			return agents[i].JoinTime.Before(agents[j].JoinTime)
		}

		// 比较最后可用时间
		return activityI.LastAvailableTime.Before(activityJ.LastAvailableTime)
	})

	return agents[0]
}

// selectLeastTalkTimeAgent 选择通话时间最少的座席
func (e *ACDEngine) selectLeastTalkTimeAgent(agents []*model.QueueMember) *model.QueueMember {
	if len(agents) == 0 {
		return nil
	}

	sort.Slice(agents, func(i, j int) bool {
		// 获取座席活动信息
		activityI, existsI := e.agentActivity[agents[i].AgentID]
		activityJ, existsJ := e.agentActivity[agents[j].AgentID]

		// 默认返回较早加入的座席
		if !existsI || !existsJ {
			return agents[i].JoinTime.Before(agents[j].JoinTime)
		}

		// 比较总通话时间
		return activityI.TotalTalkTime < activityJ.TotalTalkTime
	})

	return agents[0]
}

// selectLeastCallsAgent 选择接电话次数最少的座席
func (e *ACDEngine) selectLeastCallsAgent(agents []*model.QueueMember) *model.QueueMember {
	if len(agents) == 0 {
		return nil
	}

	sort.Slice(agents, func(i, j int) bool {
		// 获取座席活动信息
		activityI, existsI := e.agentActivity[agents[i].AgentID]
		activityJ, existsJ := e.agentActivity[agents[j].AgentID]

		// 默认返回较早加入的座席
		if !existsI || !existsJ {
			return agents[i].JoinTime.Before(agents[j].JoinTime)
		}

		// 比较总呼叫次数
		return activityI.TotalCalls < activityJ.TotalCalls
	})

	return agents[0]
}

// selectBestSkillMatchAgent 选择技能最匹配的座席
func (e *ACDEngine) selectBestSkillMatchAgent(agents []*model.QueueMember, call *model.CallQueueEntry) *model.QueueMember {
	if len(agents) == 0 || len(call.SkillsNeeded) == 0 {
		return agents[0]
	}

	// 计算每个座席的技能匹配度
	type AgentScore struct {
		Agent *model.QueueMember
		Score int
	}

	var scoredAgents []AgentScore

	for _, agent := range agents {
		score := e.calculateSkillMatchScore(agent.AgentID, call.SkillsNeeded)
		scoredAgents = append(scoredAgents, AgentScore{
			Agent: agent,
			Score: score,
		})
	}

	// 按匹配度排序
	sort.Slice(scoredAgents, func(i, j int) bool {
		return scoredAgents[i].Score > scoredAgents[j].Score
	})

	return scoredAgents[0].Agent
}

// selectHighestPriorityAgent 选择优先级最高的座席
func (e *ACDEngine) selectHighestPriorityAgent(agents []*model.QueueMember) *model.QueueMember {
	if len(agents) == 0 {
		return nil
	}

	sort.Slice(agents, func(i, j int) bool {
		// 按优先级降序排序
		if agents[i].Priority != agents[j].Priority {
			return agents[i].Priority > agents[j].Priority
		}
		// 优先级相同时，按加入时间排序
		return agents[i].JoinTime.Before(agents[j].JoinTime)
	})

	return agents[0]
}

// assignCallToAgent 将呼叫分配给座席
func (e *ACDEngine) assignCallToAgent(agent *model.QueueMember, call *model.CallQueueEntry) {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	// 更新座席状态为忙碌
	memberID := fmt.Sprintf("%s:%s", agent.AgentID, agent.QueueID)
	if member, exists := e.queueMembers[memberID]; exists {
		member.Status = model.AgentStatusBusy
		member.LastStateChange = time.Now()
	}

	// 更新呼叫状态
	call.Status = "ringing"
	call.HandledBy = agent.AgentID
	log.Printf("Call %s assigned to agent %s", call.CallUUID, agent.AgentID)

	// 通过FreeSWITCH转接呼叫
	if e.fsClient != nil {
		go func() {
			// 构建转接目标，假设座席有一个对应的SIP分机
			destination := fmt.Sprintf("agent_%s", agent.AgentID)
			err := e.fsClient.TransferCall(call.CallUUID, destination)
			if err != nil {
				log.Printf("Failed to transfer call %s to agent %s: %v", call.CallUUID, agent.AgentID, err)
				// 失败时恢复座席状态
				e.mutex.Lock()
				if member, exists := e.queueMembers[memberID]; exists {
					member.Status = model.AgentStatusAvailable
				}
				e.mutex.Unlock()
			} else {
				// 记录座席处理的呼叫
				e.mutex.Lock()
				if activity, exists := e.agentActivity[agent.AgentID]; exists {
					activity.TotalCalls++
				}
				e.mutex.Unlock()
			}
		}()
	}
}

// 辅助方法

// getQueueSize 获取队列大小
func (e *ACDEngine) getQueueSize(queueID string) int {
	count := 0
	for _, entry := range e.callQueueEntries {
		if entry.QueueID == queueID && entry.Status == "queued" {
			count++
		}
	}
	return count
}

// getAvailableAgentsLocked 获取队列中可用的座席(内部方法，需要锁保护)
func (e *ACDEngine) getAvailableAgentsLocked(queueID string) []*model.QueueMember {
	var availableAgents []*model.QueueMember
	for _, member := range e.queueMembers {
		if member.QueueID == queueID && member.Status == model.AgentStatusAvailable {
			availableAgents = append(availableAgents, member)
		}
	}
	return availableAgents
}

// getQueueCallsLocked 获取队列中的呼叫(内部方法，需要锁保护)
func (e *ACDEngine) getQueueCallsLocked(queueID string) []*model.CallQueueEntry {
	var calls []*model.CallQueueEntry
	for _, entry := range e.callQueueEntries {
		if entry.QueueID == queueID && entry.Status == "queued" {
			calls = append(calls, entry)
		}
	}

	// 按优先级和等待时间排序
	sort.Slice(calls, func(i, j int) bool {
		// 先按优先级排序
		if calls[i].Priority != calls[j].Priority {
			return calls[i].Priority > calls[j].Priority
		}
		// 优先级相同，按等待时间排序
		return calls[i].JoinTime.Before(calls[j].JoinTime)
	})

	return calls
}

// updateQueuePositions 更新队列中所有条目的位置
func (e *ACDEngine) updateQueuePositions(queueID string) {
	// 获取队列中的呼叫
	var calls []*model.CallQueueEntry
	for _, entry := range e.callQueueEntries {
		if entry.QueueID == queueID && entry.Status == "queued" {
			calls = append(calls, entry)
		}
	}

	// 按加入时间排序
	sort.Slice(calls, func(i, j int) bool {
		return calls[i].JoinTime.Before(calls[j].JoinTime)
	})

	// 更新位置
	for i, call := range calls {
		call.Position = i + 1
		call.WaitTime = int(time.Since(call.JoinTime).Seconds())
	}
}

// calculateSkillMatchScore 计算技能匹配分数
func (e *ACDEngine) calculateSkillMatchScore(agentID string, skillsNeeded []string) int {
	score := 0

	for _, skillID := range skillsNeeded {
		// 查找座席的技能等级
		for _, agentSkill := range e.agentSkills {
			if agentSkill.AgentID == agentID && agentSkill.SkillID == skillID {
				score += agentSkill.Level
				break
			}
		}
	}

	return score
}

// handleQueueOverflow 处理队列溢出
func (e *ACDEngine) handleQueueOverflow(entry *model.CallQueueEntry) {
	queue, exists := e.queues[entry.QueueID]
	if !exists {
		return
	}

	switch queue.OverflowStrategy {
	case model.OverflowStrategyBusy:
		// 播放忙音并挂断
		if e.fsClient != nil {
			go e.fsClient.HangupCall(entry.CallUUID)
		}
	case model.OverflowStrategyRedirect:
		// 重定向到其他队列
		if queue.OverflowTarget != "" {
			go func() {
				e.EnqueueCall(queue.OverflowTarget, entry.CallUUID, entry.CallerID, entry.Priority, entry.SkillsNeeded)
			}()
		}
	case model.OverflowStrategyVoicemail:
		// 转到语音留言
		if e.fsClient != nil {
			go func() {
				e.fsClient.TransferCall(entry.CallUUID, "voicemail")
			}()
		}
	case model.OverflowStrategyCallback:
		// 创建回拨请求
		callback := &model.CallbackRequest{
			ID:          fmt.Sprintf("callback_%d", rand.Int63()),
			QueueID:     entry.QueueID,
			CallerID:    entry.CallerID,
			RequestTime: time.Now(),
			Status:      "pending",
		}
		e.callbacks[callback.ID] = callback
		log.Printf("Created callback request %s for caller %s", callback.ID, entry.CallerID)
	case model.OverflowStrategyAnnouncement:
		// 播放公告
		if queue.OverflowTarget != "" && e.fsClient != nil {
			go func() {
				cmd := fmt.Sprintf("uuid_broadcast %s %s both", entry.CallUUID, queue.OverflowTarget)
				e.fsClient.SendAPI(cmd)
				// 播放完公告后挂断
				time.Sleep(10 * time.Second)
				e.fsClient.HangupCall(entry.CallUUID)
			}()
		}
	}

	entry.Status = "overflow"
	log.Printf("Call %s overflow handled with strategy: %s", entry.CallUUID, queue.OverflowStrategy)
}

// UpdateCallStatus 更新呼叫状态
func (e *ACDEngine) UpdateCallStatus(callUUID, status string) error {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	// 查找对应的队列条目
	var entry *model.CallQueueEntry
	for _, e := range e.callQueueEntries {
		if e.CallUUID == callUUID {
			entry = e
			break
		}
	}

	if entry == nil {
		return fmt.Errorf("call not found in any queue: %s", callUUID)
	}

	entry.Status = status

	if status == "answered" {
		// 记录通话开始时间
		entry.EndTime = time.Time{}
	} else if status == "completed" || status == "abandoned" {
		// 记录通话结束时间
		entry.EndTime = time.Now()

		// 如果有处理座席，更新其活动信息
		if entry.HandledBy != "" {
			if activity, exists := e.agentActivity[entry.HandledBy]; exists {
				// 计算通话时长
				if !entry.AnswerTime.IsZero() {
					activity.TotalTalkTime += int(time.Since(entry.AnswerTime).Seconds())
				}
			}

			// 恢复座席状态为事后处理或可用
			memberID := fmt.Sprintf("%s:%s", entry.HandledBy, entry.QueueID)
			if member, exists := e.queueMembers[memberID]; exists {
				// 这里可以配置是否进入事后处理状态
				member.Status = model.AgentStatusAvailable
				member.LastStateChange = time.Now()

				// 更新座席可用时间
				if activity, exists := e.agentActivity[entry.HandledBy]; exists {
					activity.LastAvailableTime = time.Now()
				}
			}
		}
	}

	log.Printf("Updated call %s status to %s", callUUID, status)
	return nil
}